#include "pe.h"

/****************************************************************************\
* Private Variables/Functions
\****************************************************************************/

byte *s_get_method_data(pe_file *p_pe, size_t rid_method)
{
	mdt_tbl_def *p_tbl;
	byte *p_row;
	size_t offset;

	if(!CONTAINS_METADATA(p_pe) || !rid_method)
		return NULL;

	p_tbl = p_pe->metadata.tbl_defs + TBLID_Method;

	if(rid_method > p_tbl->record_num)
		return NULL;

	p_row = p_tbl->p_data + p_tbl->record_size * (rid_method - 1);

	// RVA is the first column of Method table.
	offset = rva_to_offset(p_pe, *((u4 *)p_row));

	if(!offset)
		return NULL;

	return p_pe->p_base + offset;
}

/****************************************************************************\
* Public Functions
\****************************************************************************/

BOOL get_il_method(pe_file *p_pe, size_t rid_method, il_method *p_il)
{
	byte *p_method_data = s_get_method_data(p_pe, rid_method);

	if(!p_method_data)
		return FALSE;

	p_il->p_hdr = (IMAGE_COR_ILMETHOD *)p_method_data;

	if(COR_ILMETHOD_IS_FAT(p_il->p_hdr))
	{
		p_il->p_body = p_method_data + p_il->p_hdr->Fat.Size * 4;
		p_il->p_sect = p_il->p_hdr->Flags & CorILMethod_MoreSects ?
			round_to(p_il->p_body + p_il->p_hdr->Fat.CodeSize, 4) : NULL;
	}
	else  // tiny format
	{
		p_il->p_body = p_method_data + 1;
		p_il->p_sect = p_il->p_hdr->Flags & CorILMethod_MoreSects ?
			round_to(p_il->p_body + p_il->p_hdr->Tiny.CodeSize, 4) : NULL;
	}

	return TRUE;
}

byte *next_il_method_sect(pe_file *p_pe, byte *sect)
{
	u1 kind;

	if(!sect)
		return NULL;

	kind = *sect;
	if(!(kind & CorILMethod_Sect_MoreSects))
		return NULL;

	if(kind & CorILMethod_Sect_FatFormat)
		return sect + ((IMAGE_COR_ILMETHOD_SECT_FAT *)sect)->DataSize;
	else
		return sect + ((IMAGE_COR_ILMETHOD_SECT_SMALL *)sect)->DataSize;
}
